package com.mind.customer.handler.tongwei;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.mind.api.vo.OrderDetailResponse;
import com.mind.common.utils.DateUtils;
import com.mind.common.utils.StringUtils;
import com.mind.customer.domain.vo.HandlerData;
import com.mind.customer.domain.vo.TaskResult;
import com.mind.customer.exception.AjObjectNotFoundException;
import com.mind.customer.handler.common.CommonHandler;
import com.mind.customer.mapper.AjBasicGoodsitemMapper;
import com.mind.customer.mapper.AjBasicNoMaterialmappingMapper;
import com.mind.customer.mapper.AjObjectMapper;
import com.mind.customer.mapper.AjTicketTypeMapper;
import com.mind.system.domain.*;
import com.mind.system.mapper.SysConfigMapper;
import lombok.Data;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import jakarta.annotation.Resource;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 原单处理器
 *
 */
@Component
@Log4j2
public class BillOrderHandler {

    @Resource
    private CommonHandler commonHandler;

    @Resource
    private AjTicketTypeMapper ticketTypeMapper;

    @Resource
    private AjObjectMapper ajObjectMapper;
    @Resource
    private AjBasicGoodsitemMapper basicGoodsitemMapper;
    @Resource
    private AjBasicNoMaterialmappingMapper basicNoMaterialmappingMapper;
    @Resource
    private SysConfigMapper sysConfigMapper;


    private String originalBillFieldKey = "原料原单";

    /**
     * 处理原单数据
     *  todo 英文键值对转为中文键值对
     * @param task
     * @return
     */
    public TaskResult handler(AjTicketTask task, OrderDetailResponse.OrderDetailResult invoiceDetail) throws AjObjectNotFoundException {
        List<AjObject> ajObjectList = ajObjectMapper.selectObjectList(new AjObject() {{
            setTicketType(task.getTicketType());
            setType("OriginalOrder");
        }});
        String billFieldKey = originalBillFieldKey;
        String ticketName = "";
        if (!CollectionUtils.isEmpty(ajObjectList)) {
            billFieldKey = ajObjectList.get(0).getName();
            ticketName = ajObjectList.get(0).getName();
        }
        if (task == null) {
            throw new AjObjectNotFoundException("单据任务不存在");
        }
        // 票单匹配

        JSONObject info = JSONObject.parseObject(task.getInfo());
        JSONObject billOrder = new JSONObject();
        billOrder.putAll(info.getJSONObject("Basic"));
        billOrder.putAll(info.getJSONObject("Detail"));
        billOrder.put("pushDate", DateUtils.getDate());
        billOrder.put("TicketId", task.getTicketId());
        billOrder.put("TicketType", task.getTicketType());
        try{
            billOrder = handleFYLBZDBillOrder(task, billOrder, invoiceDetail);
        }catch (Exception e){
            log.error("处理票单匹配数据异常",e);
        }
        try{
            billOrder = handleOtherBillOrder(task, billOrder, invoiceDetail);
        }catch (Exception e){
            log.error("处理票单匹配数据异常",e);
        }
        try {
            billOrder = handleBillOrderTxtRate(billOrder);
        }catch (Exception e){
            log.error("处理是否专数据异常",e);
        }
        String finalBillFieldKey = billFieldKey;
        String finalTicketName = ticketName;
        JSONObject finalBillOrder = billOrder;
        return new TaskResult() {{
            setStatus(1);
            setOriginalData(new HashMap<String, Object>() {{
                put(originalBillFieldKey, finalBillOrder);
            }});
            setData(new HashMap<String, Object>() {{
                put(finalBillFieldKey, commonHandler.handleData(new HandlerData() {{
                    setTickCate(finalBillFieldKey);
                    setTicketType(task.getTicketType());
                    setTickName(finalTicketName);
                    setOriginalData(new JSONArray(finalBillOrder));
                }}).getResult());
            }});
        }};
    }

    private JSONObject handleFYLBZDBillOrder(AjTicketTask task, JSONObject billOrder, OrderDetailResponse.OrderDetailResult invoiceDetail) {

        if (("FYLBZD").equals(task.getTicketType()) && billOrder.containsKey("fyltickets") && billOrder.get("fyltickets") != null && invoiceDetail != null && invoiceDetail.getList() != null) {
            Set<Integer> matchedFeeNumbers = new HashSet<>();
            JSONArray goodsTickets = new JSONArray();
            JSONArray feedetails = billOrder.getJSONArray("fyltickets");
            JSONArray realFeedetails = new JSONArray();
            for (int j = 0; j < feedetails.size(); j++) {
                JSONObject feedetail = feedetails.getJSONObject(j);
                feedetail.put("goodsNumber", j + 1);
                realFeedetails.add(feedetail);
            }

            List<OrderDetailResponse.ListObject> invoiceDetailList = invoiceDetail.getList();
            for (int i = 0; i < realFeedetails.size(); i++) {
                JSONObject feedetail = realFeedetails.getJSONObject(i);
                String smallName = feedetail.getString("materialCode");
                for (int j = invoiceDetailList.size() - 1; j >= 0; j--) {
                    OrderDetailResponse.ListObject feeDetailList = invoiceDetail.getList().get(j);
                    List<Integer> resultList = new ArrayList<>();
                    JSONObject invoiceDetailInfo = (JSONObject) feeDetailList.getInvoiceInfo();
                    if (invoiceDetailInfo.containsKey("invoiceDetail") && invoiceDetailInfo.get("invoiceDetail") != null) {
                        JSONArray invoiceDetailArray = invoiceDetailInfo.getJSONArray("invoiceDetail");
                        for (int k = 0; k < invoiceDetailArray.size(); k++) {
                            boolean isMatched = false;
                            JSONObject invoiceDetailObject = invoiceDetailArray.getJSONObject(k);
                            String goodNameAbb = invoiceDetailObject.getString("goodsNameAbb");
                            String goodName = invoiceDetailObject.getString("goodsNameReal");
                            String taxrate = invoiceDetailObject.getString("taxrate");
                            List<AjBasicNoMaterialmapping> basicGoodsitems = basicNoMaterialmappingMapper.selectList(
                                    new QueryWrapper<AjBasicNoMaterialmapping>().eq("物料编码", smallName));
                            for (AjBasicNoMaterialmapping goodsitem : basicGoodsitems) {
                                if (StringUtils.isNotEmpty(goodsitem.get税率()) && CollectionUtils.contains(Arrays.asList(goodsitem.get税率().split(",")).listIterator(), taxrate))
                                    if (goodNameAbb.contains(goodsitem.get商品简称()) && goodName.contains(goodsitem.get商品名称())) {
                                        resultList.add(1);
                                        isMatched = true;
                                        break;
                                    }
                            }
                            if (!isMatched) {
                                resultList.add(2);
                            }
                        }

                    }
                    feedetail.put("ticketId", billOrder.getString("TicketId"));
                    feedetail.put("ticketType", billOrder.getString("TicketType"));
                    if (resultList.size() > 0 && resultList.stream().allMatch(x -> x == 1)) {
                        feedetail = JSONObject.parseObject(JSONObject.toJSONString(feedetail));

                        feedetail.put("matchStatus", "成功");
                        if (invoiceDetailInfo.containsKey("fileVo")) {
                            invoiceDetailInfo.remove("fileVo");
                        }
                        feedetail.putAll(invoiceDetailInfo);

                        goodsTickets.add(feedetail);
                        invoiceDetailList.remove(j);
                        matchedFeeNumbers.add(feedetail.getInteger("goodsNumber"));
                    }
                }
            }

            List<Object> notMatchedGoods = realFeedetails.stream().filter((obj) -> !matchedFeeNumbers.contains(((JSONObject) obj).getInteger("goodsNumber"))).collect(Collectors.toList());
            notMatchedGoods.forEach((obj) -> ((JSONObject) obj).put("matchStatus", "失败"));
            goodsTickets.addAll(notMatchedGoods);
            List<Object> goodsNumber = goodsTickets.stream().sorted(Comparator.comparingInt((obj) -> ((JSONObject) obj).getInteger("goodsNumber"))).collect(Collectors.toList());
            JSONArray goodsTicketsArray = new JSONArray();
            invoiceDetailList.forEach((obj) -> {
                JSONObject jsonObject = (JSONObject) obj.getInvoiceInfo();
                jsonObject.put("matchStatus", "失败");
                goodsTicketsArray.add(jsonObject);
            });
            goodsNumber.addAll(goodsTicketsArray);
            billOrder.put("goodsTickets", goodsNumber);

        }
        return billOrder;
    }

    private JSONObject handleBillOrderTxtRate(JSONObject billOrder) {
        if (billOrder.containsKey("feedetails") && billOrder.get("feedetails") != null && billOrder.containsKey("taxLineVoList") && billOrder.get("taxLineVoList") != null) {
            JSONArray deductibleVatDetails = new JSONArray();
            JSONArray feedetails = billOrder.getJSONArray("feedetails");
            JSONArray realFeedetails = new JSONArray();
            for (int j = 0; j < feedetails.size(); j++) {
                JSONObject feedetail = feedetails.getJSONObject(j);
                feedetail.put("goodsNumber", j + 1);
                realFeedetails.add(feedetail);
            }
            JSONArray taxLineVoList = billOrder.getJSONArray("taxLineVoList");
            JSONArray realTaxLineVoList = new JSONArray();
            for (int j = 0; j < taxLineVoList.size(); j++) {
                JSONObject feedetail = taxLineVoList.getJSONObject(j);
                realTaxLineVoList.add(feedetail);
            }
            Map<String, Double> fees = realFeedetails.stream().filter(obj -> {
                JSONObject jsonObject = ((JSONObject) obj);
                return "Y".equalsIgnoreCase(jsonObject.getString("isDeductibleVat")) && !"".equals(jsonObject.getString("taxRate"));
            }).collect(Collectors.groupingBy(obj -> {
                String text = ((JSONObject) obj).getString("taxRate");
                return text.replace("%", "");
            }, Collectors.summingDouble(obj -> ((JSONObject) obj).getDouble("tax"))));

            Map<String, Double> taxMap = realTaxLineVoList.stream().filter(obj -> {
                JSONObject jsonObject = ((JSONObject) obj);
                return !"".equals(jsonObject.getString("rate"));
            }).collect(Collectors.groupingBy(obj -> {
                String text = ((JSONObject) obj).getString("rate");
                return text.replace("%", "");
            }, Collectors.summingDouble(obj -> ((JSONObject) obj).getDouble("taxAmountSum"))));
            Set<String> notExistKey = taxMap.keySet();
            for (Map.Entry<String, Double> entry : fees.entrySet()) {
                if(taxMap.containsKey(entry.getKey())){
                    JSONObject deductibleVatDetail = new JSONObject();
                    deductibleVatDetail.put("feeTaxRate", entry.getKey());
                    deductibleVatDetail.put("feeTaxAmount", entry.getValue());
                    deductibleVatDetail.put("taxRate", entry.getKey());
                    deductibleVatDetail.put("taxAmount", taxMap.get(entry.getKey()));
                    deductibleVatDetails.add(deductibleVatDetail);
                    notExistKey.remove(entry.getKey());
                }else{
                    JSONObject deductibleVatDetail = new JSONObject();
                    deductibleVatDetail.put("feeTaxRate", entry.getKey());
                    deductibleVatDetail.put("feeTaxAmount", entry.getValue());
                    deductibleVatDetail.put("taxRate", "");
                    deductibleVatDetail.put("taxAmount", "");
                    deductibleVatDetails.add(deductibleVatDetail);
                }
            }
            for (String key : notExistKey) {
                JSONObject deductibleVatDetail = new JSONObject();
                deductibleVatDetail.put("feeTaxRate", "");
                deductibleVatDetail.put("feeTaxAmount", "");
                deductibleVatDetail.put("taxRate", key);
                deductibleVatDetail.put("taxAmount", taxMap.get(key));
                deductibleVatDetails.add(deductibleVatDetail);
            }
            billOrder.put("deductibleVatDetails", deductibleVatDetails);
        }
        return billOrder;
    }

    private JSONObject handleOtherBillOrder(AjTicketTask task, JSONObject billOrder, OrderDetailResponse.OrderDetailResult invoiceDetail) {
        @Data
        class CountVo {
            private String smallName;
            private Double totlaAmount;
            private Double taxAmountTotal;
            private Double amountTotal;
        }
        List<String> regexList = Arrays.asList("(19[0-9]{2}|20[0-9][0-9])[/-年]([0-1][0-9]|)([/-月]).*((0[1-9]|[12][0-9]|3[01])[-日])*", "(19[0-9]{2}|20[0-1][0-9]|20[0-9][0-9])[-/](0[1-9]|1[0-2])[-/](0[1-9]|[12][0-9]|3[01])", "(19[0-9]{2}|20[0-1][0-9]|20[0-9][0-9])(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])", "(19[0-9]{2}|20[0-1][0-9]|20[0-9][0-9])(0[1-9]|1[0-2])", "(19[0-9]{2}|20[0-1][0-9]|20[0-9][0-9])[-年](0[1-9]|1[0-2])", "(19[0-9]{2}|20[0-1][0-9]|20[0-9][0-9])\\.(0[1-9]|1[0-2])\\.(0[1-9]|[12][0-9]|3[01])", "(19[0-9]{2}|20[0-1][0-9]|20[0-9][0-9])\\.(0[1-9]|1[0-2])", "(19[0-9]{2}|20[0-1][0-9]|20[0-9][0-9])[-](0[1-9]|1[0-2])");
        SysConfig sysConfig = sysConfigMapper.checkConfigKeyUnique("extractDates_regexps");
        if(sysConfig != null && StringUtils.isNotEmpty(sysConfig.getConfigValue())){
            regexList = JSONArray.parseArray(sysConfig.getConfigValue(), String.class);
        }
        if (!("FYLBZD").equals(task.getTicketType()) && billOrder.containsKey("feedetails") && billOrder.get("feedetails") != null && invoiceDetail != null && invoiceDetail.getList() != null) {
            Set<Integer> matchedFeeNumbers = new HashSet<>();
            JSONArray goodsTickets = new JSONArray();
            JSONArray feedetails = billOrder.getJSONArray("feedetails");
            JSONArray realFeedetails = new JSONArray();
            for (int j = 0; j < feedetails.size(); j++) {
                JSONObject feedetail = feedetails.getJSONObject(j);
                feedetail.put("goodsNumber", j + 1);
                realFeedetails.add(feedetail);
            }
            Map<String, CountVo> countVoMap = new HashMap<>();
            List<OrderDetailResponse.ListObject> invoiceDetailList = invoiceDetail.getList();
            for (int i = 0; i < realFeedetails.size(); i++) {
                JSONObject feedetail = realFeedetails.getJSONObject(i);
                String smallName = feedetail.getString("subBizCatName");
                String belongsPeriod = feedetail.getString("belongsPeriod");
                for (int j = invoiceDetailList.size() - 1; j >= 0; j--) {
                    OrderDetailResponse.ListObject feeDetailList = invoiceDetail.getList().get(j);
                    List<Integer> resultList = new ArrayList<>();
                    JSONObject invoiceDetailInfo = (JSONObject) feeDetailList.getInvoiceInfo();
                    String remark = invoiceDetailInfo.getString("remark");
                    if (invoiceDetailInfo.containsKey("invoiceDetail") && invoiceDetailInfo.get("invoiceDetail") != null) {
                        JSONArray invoiceDetailArray = invoiceDetailInfo.getJSONArray("invoiceDetail");
                        for (int k = 0; k < invoiceDetailArray.size(); k++) {
                            boolean isMatched = false;
                            JSONObject invoiceDetailObject = invoiceDetailArray.getJSONObject(k);
                            String goodNameAbb = invoiceDetailObject.getString("goodsNameAbb");
                            String goodName = invoiceDetailObject.getString("goodsNameReal");
                            String taxrate = invoiceDetailObject.getString("taxrate");
                            taxrate = taxrate.replace("%", "");
                            taxrate = convertPercentageToDouble(taxrate);

                            int precise = basicGoodsitemMapper.countByPrecise(goodNameAbb, goodName, smallName, "业务小类+商品简称+商品名称，精确匹配", taxrate);
                            if (precise > 0) {
                                resultList.add(1);
                                isMatched = true;
                            }
                            List<AjBasicGoodsitem> basicGoodsitems = basicGoodsitemMapper.selectByFuzzy(goodNameAbb, goodName, smallName, "业务小类+商品简称-精确匹配，商品名称-模糊匹配");
                            for (AjBasicGoodsitem goodsitem : basicGoodsitems) {
                                if (goodName.contains(goodsitem.get商品名称()) && taxrate.equals(goodsitem.get税率())) {
                                    resultList.add(1);
                                    isMatched = true;
                                    break;
                                }
                            }
                            if (!isMatched) {
                                resultList.add(2);
                            } else {
                                if ("电话费".equals(smallName)) {

                                    try {
                                        for (String regex : regexList) {
                                            Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);

                                            Matcher matcher = pattern.matcher(remark);
                                            Set<String> periodList = new HashSet<>();
                                            while (matcher.find()) {
                                                // 打印匹配的字符串
                                                String dataStr = matcher.group();
                                                Date date = DateUtils.parseDate(dataStr);
                                                if (date != null) {
                                                    periodList.add(DateUtils.parseDateToStr("yyyy-MM", date));
                                                }
                                            }
                                            invoiceDetailInfo.put("invoicePeriod", String.join(",", periodList));
                                            if (periodList.size() > 1 || periodList.size() == 1 && !periodList.contains(belongsPeriod)) {
                                                resultList.add(2);
                                            }
                                            if(periodList.size() > 0) {
                                                break;
                                            }
                                        }
                                    } catch (Exception e) {
                                        log.error("帐期匹配失败", e);
                                        resultList.add(2);
                                    }
                                }
                            }
                        }

                    }
                    feedetail.put("ticketId", billOrder.getString("TicketId"));
                    feedetail.put("ticketType", billOrder.getString("TicketType"));
                    if (resultList.size() > 0 && resultList.stream().allMatch(x -> x == 1)) {
                        feedetail = JSONObject.parseObject(JSONObject.toJSONString(feedetail));
                        feedetail.put("matchStatus", "成功");
                        if (invoiceDetailInfo.containsKey("fileVo")) {
                            invoiceDetailInfo.remove("fileVo");
                        }
                        feedetail.putAll(invoiceDetailInfo);
                        JSONObject finalFeedetail = feedetail;
                        if(!countVoMap.containsKey(smallName)){
                            countVoMap.put(smallName, new CountVo(){{
                                setSmallName(smallName);
                                setTotlaAmount(finalFeedetail.getDouble("totlaAmount"));
                                setTaxAmountTotal(finalFeedetail.getDouble("reimbursementAmount"));
                            }});
                        }else{
//                            countVoMap.get(smallName).setTotlaAmount(countVoMap.get(smallName).getTotlaAmount()+finalFeedetail.getDouble("totlaAmount"));
                            countVoMap.get(smallName).setTaxAmountTotal(countVoMap.get(smallName).getTaxAmountTotal()+finalFeedetail.getDouble("reimbursementAmount"));
                        }
                        goodsTickets.add(feedetail);
                        invoiceDetailList.remove(j);
                        matchedFeeNumbers.add(feedetail.getInteger("goodsNumber"));
                    }
                }
            }
            List<Object> notMatchedGoods = realFeedetails.stream().filter((obj) -> !matchedFeeNumbers.contains(((JSONObject) obj).getInteger("goodsNumber"))).collect(Collectors.toList());
            notMatchedGoods.forEach((obj) -> ((JSONObject) obj).put("matchStatus", "失败"));
            goodsTickets.addAll(notMatchedGoods);
            List<Object> goodsNumber = goodsTickets.stream().sorted(Comparator.comparingInt((obj) -> ((JSONObject) obj).getInteger("goodsNumber"))).collect(Collectors.toList());
            JSONArray goodsTicketsArray = new JSONArray();
            invoiceDetailList.forEach((obj) -> {
                JSONObject jsonObject = (JSONObject) obj.getInvoiceInfo();
                jsonObject.put("matchStatus", "失败");
                goodsTicketsArray.add(jsonObject);
            });
            goodsNumber.addAll(goodsTicketsArray);
            billOrder.put("goodsTickets", goodsNumber);
            Collection<CountVo> values = countVoMap.values();
            values.forEach(countVo -> countVo.setAmountTotal(countVo.getTaxAmountTotal() - countVo.getTotlaAmount()));
            billOrder.put("countGoodsTickets", values);
        }
        return billOrder;
    }


    public static String convertPercentageToDouble(String percentageStr) {
        // 去掉百分号
        String numberStr = percentageStr.replace("%", "");
        // 将字符串转换为double
        double number = Double.parseDouble(numberStr);
        // 将百分比转换为小数
        double f = number / 100;
        String result = "0";
        if (f != 0) {
            result = String.valueOf(f);
        }
        return result;
    }
}
